#include "ClientManager.hpp"
#include "DataProxy.h"

//#include <boost/random/random_device.hpp>
//#include <boost/random/uniform_int_distribution.hpp>
#include "DataProxy.h"
#include <boost/nondet_random.hpp>
#include <sstream>

namespace netspy
{


bool ClientManager::isClientUpdated() const 
{
	return isClientUpdated_;
}

bool ClientManager::isServiceUpdated() const
{
	return isServiceUpdated_;
}


std::string ClientManager::generateHash()
 {
    std::string chars(
        "abcdefghijklmnopqrstuvwxyz"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "1234567890"
        "!@#$%^&*()"
        "~-_=+[{]{,<.>/? ");
    
    boost::random_device rng;
 	
    std::stringstream str;
    for(int i = 0; i < 32; ++i) {
        str << chars[rng()%chars.length()];
    }


    return str.str();
}



void ClientManager::initialize()
{

	clientBuffer_ = client_vec_ptr(new client_vec());
	serviceBuffer_ = service_vec_ptr(new service_vec());
	serviceMapBuffer_ = client_service_map_ptr(new client_service_map());
	
	boost::shared_ptr <DataProxy> db = DataProxy::getInstance();
	
	boost::shared_ptr<const std::vector<boost::shared_ptr<Client> > > clients = db->getClients();

	for(client_vec::const_iterator it=clients->begin(); it!=clients->end(); ++it)
	{
		clientBuffer_->push_back(*it);
	}

        boost::shared_ptr<const std::vector<boost::shared_ptr<Service> > > services = db->getServices();
	if (services.get()!=NULL)
	{
		for(service_vec::const_iterator it=services->begin(); it!=services->end(); ++it)
        	{
        	        serviceBuffer_->push_back(*it);
        	}
	}

	for(client_vec::const_iterator it=clients->begin(); it!=clients->end(); ++it)
	{
        	boost::shared_ptr<const std::vector<boost::shared_ptr<Service> > > clientServices = db->getServicesForClient((*it)->id);
		service_vec_ptr clientNewServices(new service_vec());
		for(service_vec::const_iterator cs=clientServices->begin(); cs!=clientServices->end(); ++cs)
		{
			for(service_vec::const_iterator as=serviceBuffer_->begin(); as!=serviceBuffer_->end(); ++as)
			{
				if ((*cs)->description.compare((*as)->description)==0)
				{
					clientNewServices->push_back((*as));
				}
			}
		}
		serviceMapBuffer_->insert(make_pair((*it)->hash,clientNewServices));
	}

}

ClientManager::RegisterStatus ClientManager::checkClient(const Message &message)
{

	if (message.info.hash.empty()) return NEW_CLIENT;
	
	boost::mutex::scoped_lock (resourceMutex_);
	for(client_vec::const_iterator it=clientBuffer_->begin(); it!=clientBuffer_->end(); ++it)
        {
                if ((*it)->hash.compare(message.info.hash) == 0)
                {
			isClientUpdated_=true;
		        return REUSE_CLIENT_HASH;
		}
        }


	return FORCE_NEW_CLIENT;
}


std::string ClientManager::registerClient(const Message &message)
{
	boost::mutex::scoped_lock (resouceMutex_);

	for(client_vec::const_iterator it=clientBuffer_->begin(); it!=clientBuffer_->end(); ++it)
	{
		if ((*it)->hash.compare(message.info.hash) == 0)
			return std::string("");
	}

	client_ptr newClient(new Client(message.info));
	
	newClient->hash = generateHash();
	boost::shared_ptr <DataProxy> db = DataProxy::getInstance();
	newClient->id = db->addClient(newClient->ip,newClient->port,newClient->hash,newClient->remarks);


	clientBuffer_->push_back(newClient);
	
	bool knownService = false;

	service_vec_ptr clientService(new service_vec());
		
	for(std::vector<std::string>::const_iterator it=message.service_list.begin(); it!=message.service_list.end(); ++it)
	{
		for(service_vec::const_iterator s=serviceBuffer_->begin(); s!=serviceBuffer_->end(); ++s)
		{
			if ((*it).compare((*s)->description) == 0 )
			{
				knownService = true;
				clientService->push_back((*s));
				db->setClientService(newClient->id,(*s)->id,true);
				break;
			}
		}

		if (!knownService)
		{
			service_ptr service(new Service());
			service->description = (*it);
			service->id=db->addService(service->description);
			serviceBuffer_->push_back(service);
			clientService->push_back(service);
			db->setClientService(newClient->id,service->id,true);
		}
	}

	
	serviceMapBuffer_->insert(make_pair(newClient->hash,clientService));
	std::cout<<serviceMapBuffer_->size()<<std::endl;
	isClientUpdated_ = true;	
	isServiceUpdated_ = true;
	return newClient->hash;
}


client_vec_ptr ClientManager::getClients() 
{

	boost::mutex::scoped_lock (resourceMutex_);

	client_vec_ptr clients(new client_vec());

	for (client_vec::const_iterator it=clientBuffer_->begin(); it!=clientBuffer_->end(); ++it)
	{
		clients->push_back((*it));
	}
	isClientUpdated_ = false;
	return clients;
}

client_service_map_ptr ClientManager::getClientServiceMap()
{
	return serviceMapBuffer_;
}

service_vec_ptr ClientManager::getServices()
{
        boost::mutex::scoped_lock (resourceMutex_);

        service_vec_ptr services(new service_vec());
	
	if (serviceBuffer_.get()!=NULL)
	{
        	for (service_vec::const_iterator it=serviceBuffer_->begin(); it!=serviceBuffer_->end(); ++it)
        	{
        	        services->push_back((*it));
        	}
	}        
	isServiceUpdated_ = false;
        return services;

}

}
